from pyglet.gl import *
from pyglet import image
import Behavior
import time
import Util
import CAConfig # global configuration

class FlakeyStat:
    def __init__(self, *args, **kwargs):
        self.base = kwargs.get('base') or 0
        self.mod = kwargs.get('mod') or 0
        self.cur = kwargs.get('cur') or self.base

class Mobile:
    def __init__(self,sheet):
        self.window       = CAConfig.window
        self.graphic      = image.load(sheet)
        self.direction    = "north"
        self.acceleration = 3
        self.step         = Util.cycle(2)
        self.step_frame   = 0
        self.sprites      = self.parse_graphic(self.graphic)
        self.position     = [0,0]
        self.velocity     = [0,0] # x,y
        self.sprite_height
        self.sprite_width
        # change the walking animation frame every nth
        # call to move()
        self.animation_cooldown = Util.cycle(2)

        # common statistics for all things
        self.health = FlakeyStat(base=10)
    
    # r/w, in pixels, y extent
    def get_top(self): return self.position[1] + self.sprite_height
    def set_top(self, y): self.position[1] = y - self.sprite_height
    top = property(get_top, set_top)

    # r/w, in pixels, y extent
    def get_bottom(self): return self.position[1]
    def set_bottom(self, y): self.position[1] = y
    bottom = property(get_bottom, set_bottom)

    # r/w, in pixels, x extent
    def get_left(self): return self.position[0]
    def set_left(self, x): self.position[0] = x 
    left = property(get_left, set_left)

    # r/w, in pixels, x extent
    def get_right(self): return self.position[0] + self.sprite_width
    def set_right(self, x): self.position[0] = x - self.sprite_width
    right = property(get_right, set_right)
    
    def get_center(self): 
        return (self.right + self.left)/2,(self.top + self.bottom)/2
        
    def set_velocity(self, axis, velocity ):
        if velocity:
            self.velocity[axis] += velocity
        else:
            self.velocity[axis] = 0
            
        if self.velocity[axis] > self.acceleration:
            self.velocity[axis] = self.acceleration
        elif self.velocity[axis] < -self.acceleration:
            self.velocity[axis] = -self.acceleration
            
    def update(self, offset):
        if self.velocity[0] != 0 or self.velocity[1] != 0:
            self.update_direction()
            self.move()
        self.draw(offset)
    
    def move(self):
        # should check for collision of course...
        new_x = self.position[0] + self.velocity[0]
        new_y = self.position[1] + self.velocity[1]
        if Util.between( new_x, 0, CAConfig.map_size[0] - self.sprite_width ):
            self.position[0] = new_x
        if Util.between( new_y, 0, CAConfig.map_size[1] - self.sprite_height ):
            self.position[1] = new_y
        if self.animation_cooldown.next() == 0:
            self.step_frame = self.step.next()
   
    def get_rect(self,sub_rect=0):
        """
        Returns coords of the image.
        2 - 3
        |   |
        1 - 4
        sub_rect is used to build a larger or smaller rectangle based upon
        the current position. It is useful for checking for collisions.
        """
        x,y = self.position[0]+sub_rect,self.position[1]-sub_rect
        w,h = self.graphic.height-sub_rect,self.graphic.width+sub_rect
        bottom_left  = x,y
        bottom_right = x+w,y
        top_left     = x,y+h
        top_right    = x+w,y+h
        return (bottom_left,top_left,top_right,bottom_right)
   
    def collides(self,other):
        if self.right < other.left: return False
        if other.right < self.left: return False
        if self.top < other.bottom: return False
        if other.top < self.bottom: return False
        return True
          
    def draw(self, offset):
        offset_x,offset_y = offset
        sprite     = self.sprites[self.direction][self.step_frame]
        sprite.blit(self.position[0] - offset_x, self.position[1] - offset_y)
    
    def update_direction(self):
        # save the current direction for a later
        # comparison
        current_direction = self.direction
        # figure out the direction
        if self.velocity[1] < 0:
            self.direction = "south"
        if self.velocity[1] > 0:
            self.direction = "north"
        if self.velocity[0] > 0:
            self.direction = "east"
        if self.velocity[0] < 0:
            self.direction = "west"
        # if the direction has changed, reset the frame cycle
        if self.direction != current_direction:
            self.step = Util.cycle()
            
    # character graphics are arranged like this:
    # N0 N1 N2
    # E0 E1 E2
    # S0 S1 S2
    # W0 W1 W2
    def parse_graphic(self, graphic, dimensions=(24,32)):
        self.sprite_width,self.sprite_height = width,height = dimensions
        dirs = ('west','south','east','north')
        sprite_cache = {}
        
        for row in xrange(0, height*4, height):
            _row = row/height
            d = dirs[_row]
            sprite_cache[d] = tuple([
                graphic.get_region(x*width, _row*height, width, height) 
                    for x in (0,1,2)])
        
        return sprite_cache

class ScriptedMobile(Mobile):
    
    def __init__(self, *args, **kwargs):
        Mobile.__init__(self, *args)
        self.behavior = kwargs.get('behavior')
        self.behavior_timer = time.time()
    
    def update(self, offset):
        try:
            self.behavior(self)
        except Exception, e:
            print e
        Mobile.update(self, offset)
